﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using LowLevelGraphics.Extensions;

namespace LowLevelGraphics.Filter
{
    //TODO: implement
    /// <summary>
    ///Neighborhood operations on binary images using lookup tables
    ///Syntax
    ///
    ///A = applylut(BW,LUT)
    ///Description
    ///
    ///A = applylut(BW,LUT) performs a 2-by-2 or 3-by-3 neighborhood operation on binary image BW by using a lookup table (LUT).
    ///LUT is either a 16-element or 512-element vector returned by makelut.
    ///The vector consists of the output values for all possible 2-by-2 or 3-by-3 neighborhoods.

    ///Class Support
    ///
    ///BW can be numeric or logical, and it must be real, two-dimensional, and nonsparse.
    ///LUT can be numeric or logical, and it must be a real vector with 16 or 512 elements.
    ///If all the elements of LUT are 0 or 1, then A is logical. 
    ///If all the elements of LUT are integers between 0 and 255, then A is uint8. 
    ///For all other cases, A is double.
    ///
    ///Algorithm
    ///
    ///applylut performs a neighborhood operation on a binary image by producing a matrix of indices into lut,
    ///and then replacing the indices with the actual values in lut. 
    ///The specific algorithm used depends on whether you use 2-by-2 or 3-by-3 neighborhoods.

    ///2-by-2 Neighborhoods
    ///
    ///For 2-by-2 neighborhoods, length(lut) is 16. 
    ///There are four pixels in each neighborhood, and two possible states for each pixel, so the total number of permutations is 24 = 16.
    ///
    ///To produce the matrix of indices, applylut convolves the binary image BW with this matrix.
    ///
    ///8     2
    ///4     1
    ///
    ///The resulting convolution contains integer values in the range [0,15]. 
    ///applylut uses the central part of the convolution, of the same size as BW, and adds 1 to each value to shift the range to [1,16].
    ///It then constructs A by replacing the values in the cells of the index matrix with the values in lut that the indices point to.

    ///3-by-3 Neighborhoods
    ///
    ///For 3-by-3 neighborhoods, length(lut) is 512.
    ///There are nine pixels in each neighborhood, and two possible states for each pixel, so the total number of permutations is 29 = 512.
    ///
    ///To produce the matrix of indices, applylut convolves the binary image BW with this matrix.
    ///
    ///256    32     4
    ///128    16     2
    ///64     8     1
    ///
    ///The resulting convolution contains integer values in the range [0,511]. applylut uses the central part of the convolution, of the same size as BW, and adds 1 to each value to shift the range to [1,512]. It then constructs A by replacing the values in the cells of the index matrix with the values in lut that the indices point to.
    ///Examples
    ///
    ///Perform erosion using a 2-by-2 neighborhood. An output pixel is on only if all four of the input pixel's neighborhood pixels are on.
    ///
    ///lut = makelut('sum(x(:)) == 4',2);
    ///BW = imread('text.png');
    ///BW2 = applylut(BW,lut);
    ///imshow(BW), figure, imshow(BW2)    /// </summary>
    public class ApplyLut : BaseImageFilter
    {
        protected Neighbours m_aNeighbour = new Neighbours();
        protected NeighbouringDelegate m_NeighbouringDelegate = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="ApplyLut"/> class.
        /// </summary>
        public ApplyLut()
        {
            this.m_NeighbouringDelegate = new NeighbouringDelegate(NeighbouringDefaultDelegateSignatur);
            this.m_aNeighbour = new Neighbours() { new Neighbour(3, 3), new Neighbour(-3, -3) };
            this.m_aNeighbour = new Neighbours() { new Neighbour(-3, 3), new Neighbour(3, -3) };
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ApplyLut"/> class.
        /// </summary>
        /// <param name="_applyLut">The _apply lut.</param>
        internal ApplyLut(ApplyLut _applyLut)
        {
        }

        /// <summary>
        /// Gets or sets the neighbours.
        /// </summary>
        /// <value>The neighbours.</value>
        public Neighbours Neighbours
        {
            get { return m_aNeighbour; }
            set { m_aNeighbour = value; }
        }

        /// <summary>
        /// the neighbouring delegate.
        /// </summary>
        /// <value>The neighbouring delegate.</value>
        public NeighbouringDelegate NeighbouringDelegate
        {
            get { return m_NeighbouringDelegate; }
            set { m_NeighbouringDelegate = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int[] aMatrix = new int[] { 0, 1, 0, 1, 0 };
            UnsafeBitmap bitmapCloned = new UnsafeBitmap((UnsafeBitmap)_bitmap.Clone());
            UnsafeBitmap bitmap = _bitmap;
            Pixel.Bitmap = bitmapCloned;
            Pixel.SetNeighbours(this.m_aNeighbour);
            Color color = Color.Transparent;
            foreach (Pixel pixel in
                bitmapCloned.GetPixels(
                    new Rectangle(0, 0, bitmapCloned.Width, bitmapCloned.Height)))
            {
                int nCount = 0;
                foreach (int i in aMatrix)
                {
                    if (i == (pixel.Color.ToArgb() > 0 ? 1 : 0))
                    {
                        //TODO: implement
                        //_bitmap.SetPixel(x,y,
                    }
                }
            }
            bitmapCloned.Dispose();
            return _bitmap;
        }

        /// <summary>
        /// This is just a simple filter if no parameters are given 
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <param name="pixel"></param>
        /// <returns></returns>
        private Color NeighbouringDefaultDelegateSignatur(UnsafeBitmap _bitmap, Pixel pixel)
        {
            float fSumBrightness = 0;
            Color color = Color.Transparent;
            Neighbour neighbour = null;
            while (pixel.Neighbours.MoveNext())
            {
                neighbour = (Neighbour)pixel.Neighbours.Current;
                color = neighbour.Color;
                fSumBrightness += Color.FromArgb(color.R, 0, 0).GetBrightness();
                fSumBrightness += Color.FromArgb(0, color.G, 0).GetBrightness();
                fSumBrightness += Color.FromArgb(0, 0, color.B).GetBrightness();
            }
            fSumBrightness = fSumBrightness / (m_aNeighbour.Count + 3.0f) * 256;
            int nSumBrightness = (int)fSumBrightness;
            return Color.FromArgb(nSumBrightness, nSumBrightness, nSumBrightness);
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ApplyLut(this);
        }
    }
}
